/**
 * 
 */
package de.cbf.cam.dsa.battle.ui.composites;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;

import de.cbf.cam.dice.entities.RollData;
import de.cbf.cam.dice.entities.RollDataCheck;
import de.cbf.cam.dice.entities.RollDataCheckEditable;
import de.cbf.cam.dice.entities.RollDataOpen;
import de.cbf.cam.dice.entities.RollDataSum;
import de.cbf.cam.dice.interfaces.IDiceCompositeActionListener;

/**
 * @author  Nebelritter
 */
public abstract class CompositeDiceRoll extends Composite {	
	
	/**
	 * Result is the modified result of dice throw 
	 */
	public static final int EVENT_ResultModify  = 1;	
	/**
	 * listeners for the rolling of dice
	 */
	public static final int EVENT_RollDice 		= 2;
	public static final int EVENT_RollModify	= 3;
	
	/**
	 * @uml.property  name="resultModifyListeners"
	 * @uml.associationEnd  multiplicity="(0 -1)" elementType="java.awt.event.ActionListener"
	 */
	protected List<ActionListener> resultModifyListeners 	= new ArrayList<ActionListener>();
	/**
	 * @uml.property  name="rollModifyListeners"
	 * @uml.associationEnd  multiplicity="(0 -1)" elementType="java.awt.event.ActionListener"
	 */
	protected List<ActionListener> rollModifyListeners	 	= new ArrayList<ActionListener>();
	/**
	 * @uml.property  name="rollDiceListeners"
	 * @uml.associationEnd  multiplicity="(0 -1)" elementType="java.awt.event.ActionListener"
	 */
	protected List<ActionListener> rollDiceListeners 		= new ArrayList<ActionListener>();
	
	/**
	 * @uml.property  name="title"
	 */
	protected String  title ="";
	
	public abstract void enable();

	public abstract void disable();

	public abstract void setModifierValue(int value);
	
	public abstract void setModifierText(List<String> text);
	
	public abstract int[] 	getRolls();
	/**
	 * @uml.property  name="result"
	 */
	public abstract Integer getResult();
	
	/**
	 * can be overridden for own dispose actions
	 */
	protected  void disposeSelf(){
		;
	}
	
	protected abstract List<ActionListener> getAllRegisteredListeners();
	
	/**
	 * @uml.property  name="throwDataPCL"
	 */
	protected abstract PropertyChangeListener getThrowDataPCL();

	public CompositeDiceRoll(Composite parent, int style) {
		super(parent, style);	
		buildContent(parent);
	}

	protected abstract void buildContent(Composite parent) ;

	/**
	 * @return
	 * @uml.property  name="title"
	 */
	public String getTitle() {
		return title;
	}

	/**
	 * @param title
	 * @uml.property  name="title"
	 */
	public void setTitle(String title) {
		this.title = title;
	}
	/**
	 * Do not try to overwrite this dispose, use Dispose self for own dispose actions
	 */
	@Override
	public final void dispose() {
		for (ActionListener listener : getAllListeners()) {
			if (listener instanceof IDiceCompositeActionListener) {
				IDiceCompositeActionListener compositeActionListener = (IDiceCompositeActionListener) listener;
				compositeActionListener.dispose();
			}
		}
		disposeSelf();
		super.dispose();
	}		
//====================
//	Event Listener Registry
//====================	
	public List<ActionListener> getAllListeners(){
		List<ActionListener> resultList = new ArrayList<ActionListener>();
		resultList.addAll(resultModifyListeners);
		resultList.addAll(rollDiceListeners);
		resultList.addAll(getAllRegisteredListeners());
		return resultList;
	}
	
	public void clearListeners(){
		resultModifyListeners.clear();
		rollDiceListeners.clear();
	}
	
	public boolean addEventListener(ActionListener listener,int event){
		switch (event) {
		case EVENT_RollDice:{
			return registerRollDiceListener(listener);			
		}
		case EVENT_ResultModify:{
			return registerResultModifyListener(listener);			
		}
		case EVENT_RollModify:{
			return registerRollModifyListener(listener);			
		}
		default:
			return false;			
		}
	}
	public boolean removeEventListener(ActionListener listener,int event){
		switch (event) {
		case EVENT_RollDice:{
			return deregisterRollDiceListener(listener);			
		}
		case EVENT_ResultModify:{
			return deregisterResultModifyListener(listener);			
		}
		case EVENT_RollModify:{
			return deregisterRollModifyListener(listener);			
		}
		default:
			return false;
		}
	}

	public boolean registerResultModifyListener(ActionListener listener){
		return resultModifyListeners.add(listener);
	}	
	public boolean deregisterResultModifyListener(ActionListener listener){
		return resultModifyListeners.remove(listener);
	}
	
	public boolean registerRollModifyListener(ActionListener listener){
		return rollModifyListeners.add(listener);
	}	
	public boolean deregisterRollModifyListener(ActionListener listener){
		return rollModifyListeners.remove(listener);
	}
	
	public boolean registerRollDiceListener(ActionListener listener){
		return rollDiceListeners.add(listener);
	}	
	public boolean deregisterRollDiceListener(ActionListener listener){
		return rollDiceListeners.remove(listener);
	}

//==================
//	Event Listeners (to notify ThrowData)
//==================
	
	public static void addListeners(final RollData data,final CompositeDiceRoll compositeDice){
		compositeDice.addEventListener(new ActionListener() {			
			@Override
			public void actionPerformed(ActionEvent e) {				
				data.setRolls(compositeDice.getRolls());				
			}
		}, CompositeDiceRollCheck.EVENT_RollModify);
	}
		
	public static void addListenersCheck(final RollDataCheck dataCheck,final CompositeDiceRollCheck compositeDiceCheck){
		addListeners(dataCheck, compositeDiceCheck);
		compositeDiceCheck.addEventListener(new ActionListener() {			
			@Override
			public void actionPerformed(ActionEvent e) {				
				dataCheck.setSuccess(compositeDiceCheck.getSuccess());				
			}
		}, CompositeDiceRollCheck.EVENT_SuccessModify);			
	}
	
	public static CompositeDiceRoll getCompositeForThrow(RollData throwData,Composite parent){
		if (throwData instanceof RollDataCheck) { 
			RollDataCheck throwDataCheck = (RollDataCheck) throwData;			
			CompositeDiceRollCheck composite = new CompositeDiceRollCheck(parent,SWT.NONE);				
			//
			composite.setBase			(throwDataCheck.getBase());			
			composite.setTitle			(throwDataCheck.getName());
			composite.setIgnoreNegatives(throwDataCheck.isIgnoreNegatives());
			composite.setModifierText	(throwDataCheck.getModifierText());
			composite.setModifierValue	(throwDataCheck.getModifierValue());			
			//
			addListenersCheck(throwDataCheck,composite);
			throwDataCheck.propertyChange.addPropertyChangeListener(composite.getThrowDataPCL());
			return composite;			
		}
		if (throwData instanceof RollDataCheckEditable) {
			RollDataCheckEditable throwDataCheck = (RollDataCheckEditable) throwData;
			CompositeDiceRollCheck composite = new CompositeDiceRollCheck(parent,SWT.NONE|CompositeDiceRollCheck.EDIT_BASE);
			
			composite.setBase			(throwDataCheck.getBase());			
			composite.setTitle			(throwDataCheck.getName());
			composite.setIgnoreNegatives(throwDataCheck.isIgnoreNegatives());
			composite.setModifierText	(throwDataCheck.getModifierText());
			composite.setModifierValue	(throwDataCheck.getModifierValue());	
			addListenersCheck(throwDataCheck,composite);
			throwDataCheck.propertyChange.addPropertyChangeListener(composite.getThrowDataPCL());
			return composite;
		}
		if (throwData instanceof RollDataSum) {			
			RollDataSum throwDataSum = (RollDataSum) throwData;		
			// Check dice side to return Composite for ThrowDataSum			
			if(throwDataSum.getRollDataSubCount() > 1){
				CompositeRollXDiceOpen compositeXDiceOpen = new CompositeRollXDiceOpen(parent, SWT.NONE);
				//add subcomponents
				for (int i = 0; i < throwDataSum.getRollDataSubCount(); i++) {
					RollDataOpen throwDataSub = throwDataSum.getRollDataSub(i);
					CompositeDiceRollOpen compositeSub = 
						compositeXDiceOpen.addDiceCompositeSub(SWT.NORMAL,throwDataSub.getDiceSides()[0]);
					//add listeners to sub components
					addListeners(throwDataSub, compositeSub);
					throwDataSub.propertyChange.addPropertyChangeListener(compositeSub.getThrowDataPCL());
				}			
				//
				compositeXDiceOpen.setTitle(throwDataSum.getName());				
				compositeXDiceOpen.setModifierText(throwDataSum.getModifierText());
				compositeXDiceOpen.setModifierValue(throwDataSum.getModifierValue());			
				//			
				addListeners(throwDataSum, compositeXDiceOpen);
				throwDataSum.propertyChange.addPropertyChangeListener(compositeXDiceOpen.getThrowDataPCL());
				return compositeXDiceOpen;
			}else{
				CompositeDiceRollOpen compositeDiceOpen = new CompositeDiceRollOpen(parent, SWT.NORMAL|CompositeDiceRollOpen.WITH_MODIFIER);
				compositeDiceOpen.setDiceSides( throwDataSum.getDiceSides());
				//
				compositeDiceOpen.setTitle(throwDataSum.getName());				
				compositeDiceOpen.setModifierText(throwDataSum.getModifierText());
				compositeDiceOpen.setModifierValue(throwDataSum.getModifierValue());			
				//			
				addListeners(throwDataSum, compositeDiceOpen);
				throwDataSum.propertyChange.addPropertyChangeListener(compositeDiceOpen.getThrowDataPCL());
				return compositeDiceOpen;
			}
			
		}
		
		System.err.print("throwDataType:" +throwData.getClass().getSimpleName() + " not implemented yet");
		return null;
	}

}
